package com.uinnova.product.eam.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.binary.core.exception.BinaryException;
import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.uinnova.product.eam.comm.model.es.AssetWarehouseDir;
import com.uinnova.product.eam.comm.model.es.EamCategory;
import com.uinnova.product.eam.dto.AXEAClassMapping;
import com.uinnova.product.eam.dto.AXEAConf;
import com.uinnova.product.eam.dto.ArchReviewConf;
import com.uinnova.product.eam.model.cj.domain.*;
import com.uinnova.product.eam.model.cj.request.PlanDesignInstanceAddRequest;
import com.uinnova.product.eam.model.cj.vo.*;
import com.uinnova.product.eam.model.enums.AssetType;
import com.uinnova.product.eam.model.es.PlanProcessRelation;
import com.uinnova.product.eam.service.*;
import com.uinnova.product.eam.service.cj.dao.ChapterContextDao;
import com.uinnova.product.eam.service.cj.dao.DeliverableTemplateDao;
import com.uinnova.product.eam.service.cj.dao.PlanDesignInstanceDao;
import com.uinnova.product.eam.service.cj.dao.TemplateTypeDao;
import com.uinnova.product.eam.service.cj.service.DeliverableTemplateService;
import com.uinnova.product.eam.service.cj.service.PlanChapterInstanceService;
import com.uinnova.product.eam.service.cj.service.PlanDesignInstanceService;
import com.uinnova.product.eam.vo.CheckPlanModuleReq;
import com.uinnova.product.eam.vo.CheckPlanModuleRes;
import com.uinnova.product.eam.vo.PlanPublishDirInfo;
import com.uinnova.product.eam.vo.PlanPublishDirReq;
import com.uinnova.product.vmdb.comm.model.ci.CCcCiClass;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiInfo;
import com.uinnova.product.vmdb.provider.ci.bean.CiGroupPage;
import com.uino.api.client.permission.IUserApiSvc;
import com.uino.bean.cmdb.base.ESCIClassInfo;
import com.uino.bean.cmdb.base.ESCIInfo;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.cmdb.query.ESCISearchBean;
import com.uino.bean.permission.base.SysUser;
import com.uino.bean.permission.query.CSysUser;
import com.uino.service.cmdb.microservice.impl.CIClassSvc;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.util.Asserts;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Log4j2
public class PlanServiceImpl implements PlanService {

    @Autowired
    private DeliverableTemplateDao deliverableTemplateDao;
    @Autowired
    private CIClassSvc ciClassSvc;
    @Autowired
    private IamsCISwitchSvc ciSwitchSvc;
    @Autowired
    private AXEAConfService axeaConfService;
    @Autowired
    private EamCategorySvc categorySvc;
    @Autowired
    private AssetWarehouseDirSvc assetWarehouseDirSvc;
    @Autowired
    private PlanDesignInstanceService planDesignInstanceService;
    @Resource
    private IUserApiSvc userApiSvc;

    @Value("${http.resource.space}")
    private String httpResourceUrl;

    @Autowired
    private DeliverableTemplateService deliverableTemplateService;

    @Autowired
    private TemplateTypeDao templateTypeDao;

    @Resource
    private PlanDesignInstanceDao planDesignInstanceDao;
    @Resource
    private PlanChapterInstanceService planChapterInstanceService;
    @Resource
    private ChapterContextDao chapterContextDao;
    @Resource
    private PlanProcessRelationService planProcessRelationService;

    @Override
    public PlanPublishDirInfo getPlanPublishDirInfo(PlanPublishDirReq req) {
        Assert.notNull(req, "模板id不能为空");
        Assert.notNull(req.getDeliverableTemplateId(), "模板id不能为空");
        //查模板
        DeliverableTemplate deliverableTemplate = deliverableTemplateDao.getById(req.getDeliverableTemplateId());
        Assert.notNull(deliverableTemplate, "未找到方案模板");
        //查绑定资产
        String defaultSystemCiCode = req.getDefaultSystemCiCode();
        List<ESCIInfo> esciInfos = ciSwitchSvc.getCiByCodes(Arrays.asList(defaultSystemCiCode), null, LibType.DESIGN);
        if (CollectionUtils.isEmpty(esciInfos)) {
            return getDeliverableTemplateDir(deliverableTemplate);
        }
        ESCIInfo ciInfo = esciInfos.get(0);
        List<BindAssetVo> bindAssetList = deliverableTemplate.getBindAssetList();
        BindAssetVo bindAssetVo = bindAssetList.get(0);
        //绑定资产对应的分类和模板绑定资产分类不一致
        if (!bindAssetVo.getClassId().equals(ciInfo.getClassId())) {
            throw new BinaryException("绑定资产所属分类与模板绑定分类不一致");
        }
        CCcCiClass cdt = new CCcCiClass();
        cdt.setId(bindAssetVo.getClassId());
        List<CcCiClassInfo> classInfos = ciClassSvc.queryClassByCdt(cdt);
        if (CollectionUtils.isEmpty(classInfos)) {
            log.error("未找到模板绑定分类:ciClassId:{}", bindAssetVo.getClassId());
            throw new BinaryException("未找到模板绑定分类");
        }
        CcCiClassInfo ciClassInfo = classInfos.get(0);
        AXEAConf axeaConf = axeaConfService.getCategoryAutoConf();
        //模板非指定需要创建系统文件夹分类
        if (!axeaConf.getClassConf().containsKey(ciClassInfo.getCiClass().getClassCode())) {
            return getDeliverableTemplateDir(deliverableTemplate);
        }
        //查资产仓库系统文件夹
        EamCategory category = categorySvc.getByCiCode(defaultSystemCiCode, null, LibType.DESIGN);
        if (category == null) {
            return getDeliverableTemplateDir(deliverableTemplate);
        }
        //有绑定资产对应的系统文件夹
        List<Long> dirPathIds = new ArrayList<>();
        String dirPath = category.getDirPath().substring(1, category.getDirPath().length() - 1);
        String[] pathIds = dirPath.split("#");
        for (String pathId : pathIds) {
            dirPathIds.add(Long.valueOf(pathId));
        }
        List<EamCategory> categories = categorySvc.getByIds(dirPathIds, LibType.DESIGN);
        Map<String, String> categoryMap = categories.stream().collect(
                Collectors.toMap(c -> c.getId().toString(), EamCategory::getDirName));
        AssetWarehouseDir assetWarehouseDir = assetWarehouseDirSvc.getById(Long.valueOf(pathIds[0]));
        StringBuilder stringBuilder = new StringBuilder();
        if (assetWarehouseDir != null) {
            stringBuilder.append(assetWarehouseDir.getName());
        }
        for (String pathId : pathIds) {
            stringBuilder.append("/").append(categoryMap.getOrDefault(pathId, ""));
        }
        PlanPublishDirInfo dirInfo = new PlanPublishDirInfo();
        dirInfo.setAssertDirEdit(false);
        dirInfo.setAssetsDirId(category.getId());
        dirInfo.setEchoDirName(stringBuilder.toString());
        dirInfo.setDomainDirId(Long.valueOf(pathIds[0]));
        return dirInfo;
    }

    private PlanPublishDirInfo getDeliverableTemplateDir(DeliverableTemplate deliverableTemplate) {
        PlanPublishDirInfo dirInfo = new PlanPublishDirInfo();
        dirInfo.setAssertDirEdit(true);
        Long assetsDirId = deliverableTemplate.getAssetsDirId();
        //模板没有发布位置
        if (StringUtils.isBlank(deliverableTemplate.getEchoDirName()) || assetsDirId == null) {
            return dirInfo;
        }
        EamCategory eamCategory = categorySvc.getById(assetsDirId, LibType.DESIGN);
        //模板的发布位置不存在
        if (eamCategory == null) {
            return dirInfo;
        }
        dirInfo.setAssertDirEdit(false);
        dirInfo.setAssetsDirId(assetsDirId);
        dirInfo.setDomainDirId(deliverableTemplate.getDomainDirId());
        dirInfo.setEchoDirName(deliverableTemplate.getEchoDirName());
        return dirInfo;
    }

    @Override
    public Long save(PlanDesignInstanceAddRequest request) {
        return planDesignInstanceService.add(request);
    }

    @Override
    public Page<DiagramPlanVO> getAllPlans(JSONObject jsonObject) {
        Page<DiagramPlanVO> result = new Page<>();
        String pageNum = jsonObject.getString("pageNum");
        String pageSize = jsonObject.getString("pageSize");
        Asserts.notNull(pageNum, "pageNum");
        Asserts.notNull(pageSize, "pageSize");
        result.setPageNum(Long.parseLong(pageNum));
        result.setPageSize(Long.parseLong(pageSize));

        List<DiagramPlanVO> diagramPlanList = new ArrayList<>();
        // 查询条件
        // 方案名称/关联资产名称
        String name = jsonObject.getString("name");
        String creators = jsonObject.getString("creators");
        String templateId = jsonObject.getString("templateId");
        // 资产状态 0：未发布，1：已发布，2：审批中，3：审核中可编辑
        String releaseStatus = jsonObject.getString("releaseStatus");
        // 关联资产分类-classId
        String ciClassId = jsonObject.getString("ciClassId");
        // 关联资产-ciCode
        String ciCode = jsonObject.getString("ciCode");

        // 如果name不为空 需要根据name查询关联资产列表
        List<String> ciCodesByName = new ArrayList<>();
        if (!BinaryUtils.isEmpty(name)) {
            List<CcCiInfo> ciList = getCiListByName(name);
            if (!BinaryUtils.isEmpty(ciList)) {
                ciCodesByName = ciList.stream().map(ciInfo -> ciInfo.getCi().getCiCode()).collect(Collectors.toList());
            }
        }

        Page<PlanDesignInstance> planDesignPage = planDesignInstanceService.findAllPlanList(Integer.valueOf(pageNum), Integer.valueOf(pageSize), name, creators, templateId, releaseStatus, ciClassId, ciCode, ciCodesByName);
        if(CollectionUtils.isEmpty(planDesignPage.getData())){
            result.setTotalRows(0l);
            result.setTotalPages(0l);
            result.setData(diagramPlanList);
            return result;
        }
        Set<String> loginCodeSet = new HashSet<>();
        List<String> ciCodes = new ArrayList<>();
        List<Long> ciClassIds = new ArrayList<>();
        for (PlanDesignInstance plan : planDesignPage.getData()) {
            if (!StringUtils.isEmpty(plan.getCreatorCode())) {
                loginCodeSet.add(plan.getCreatorCode());
            }
            if (!StringUtils.isEmpty(plan.getModifierCode())) {
                loginCodeSet.add(plan.getModifierCode());
            }
            if (!StringUtils.isEmpty(plan.getDefaultSystemCiCode())) {
                ciCodes.add(plan.getDefaultSystemCiCode());
            }
            if (!BinaryUtils.isEmpty(plan.getDefaultSystemClassId())) {
                ciClassIds.add(plan.getDefaultSystemClassId());
            }
        }
        // 查询关联资产 再与方案做匹配
        List<ESCIInfo> ciList = ciSwitchSvc.getCiByCodes(ciCodes, null, LibType.DESIGN);
        Map<String, ESCIInfo> ciCodeMap = ciList.stream().collect(Collectors.toMap(ESCIInfo::getCiCode, e -> e, (k1, k2) -> k2)); // ciCode-ci
        List<ESCIClassInfo> classInfos = ciClassSvc.queryESClassInfoByIds(ciClassIds);
        Map<Long, String> ciClassMap = classInfos.stream().collect(Collectors.toMap(ESCIClassInfo::getId, ESCIClassInfo::getClassName));// ciClassId-ciClassName

        Map<String, SysUser> userMap = queryUserMap(loginCodeSet);
        for (PlanDesignInstance plan : planDesignPage.getData()) {
            DiagramPlanVO diagramPlan = new DiagramPlanVO();
            diagramPlan.setCreator(userMap.get(plan.getCreatorCode()));
            PlanDesignResponseVO responseVO = new PlanDesignResponseVO();
            BeanUtils.copyProperties(plan, responseVO);
            if (userMap.get(plan.getCreatorCode()) != null) {
                responseVO.setCreatorName(userMap.get(plan.getCreatorCode()).getUserName());
            }
            if (userMap.get(plan.getModifierCode()) != null) {
                responseVO.setModifierName(userMap.get(plan.getModifierCode()).getUserName());
            }
            diagramPlan.setPlanDesignInstance(responseVO);
            diagramPlan.setAssetType(AssetType.SCHEME);
            diagramPlan.setModifyTime(plan.getModifyTime());
            diagramPlan.setCreateTime(plan.getCreateTime());
            // 设置方案状态
            if (!BinaryUtils.isEmpty(plan.getStatus())) {
                if ("draft".equals(plan.getStatus())) {
                    if (plan.isProcessApproval()) {
                        diagramPlan.setReleaseStatus(2);
                    } else {
                        diagramPlan.setReleaseStatus(0);
                    }
                } else if ("approve".equals(plan.getStatus())) {
                    diagramPlan.setReleaseStatus(2);
                } else if ("approve_edit".equals(plan.getStatus())) {
                    diagramPlan.setReleaseStatus(3);
                } else if ("published".equals(plan.getStatus())) {
                    diagramPlan.setReleaseStatus(1);
                }
            }
            // 方案关联资产绑定
            diagramPlan.setCiName("-");
            diagramPlan.setCiClassName("-");
            ESCIInfo ciInfo = ciCodeMap.get(plan.getDefaultSystemCiCode());
            if (!BinaryUtils.isEmpty(ciInfo)) {
                String className = ciClassMap.get(ciInfo.getClassId());
                diagramPlan.setCiName(getSysName(ciInfo));
                diagramPlan.setCiClassName(className);
            }
            diagramPlanList.add(diagramPlan);
        }
        result.setTotalRows(planDesignPage.getTotalRows());
        result.setTotalPages(planDesignPage.getTotalPages());
        result.setData(diagramPlanList);
        return result;
    }

    private List<CcCiInfo> getCiListByName(String name) {
        ArchReviewConf archReviewConf = axeaConfService.getArchReviewConf();
        //无label字段时返回空
        List<String> labelDefs = getLabelDefs(archReviewConf.getProjectClassId());
        if (CollectionUtils.isEmpty(labelDefs)) {
            return null;
        }
        AXEAClassMapping axeaClassMapping = axeaConfService.getSystemClassMapping();
        labelDefs = getLabelDefs(axeaClassMapping.getSystemClassId());
        if (CollectionUtils.isEmpty(labelDefs)) {
            return null;
        }
        List<CcCiInfo> result = new ArrayList<>();
        int pageNum = 1;
        int pageSize = 50;
        ESCISearchBean bean = new ESCISearchBean();
        bean.setSortField("modifyTime");
        bean.setAsc(false);
        bean.setWordLabel(true);
        bean.setWords(Arrays.asList(name));
        bean.setClassIds(Arrays.asList(archReviewConf.getProjectClassId(), axeaClassMapping.getSystemClassId()));
        bean.setDomainId(1L);
        bean.setPageNum(pageNum);
        bean.setPageSize(pageSize);
        CiGroupPage page = ciSwitchSvc.queryPageBySearchBean(bean, false, LibType.DESIGN);
        if (!CollectionUtils.isEmpty(page.getData())) {
            result.addAll(page.getData());
        }
        for (int i = 2; i <= page.getTotalPages(); i++ ) {
            bean.setPageNum(i);
            page = ciSwitchSvc.queryPageBySearchBean(bean, false, LibType.DESIGN);
            if (!CollectionUtils.isEmpty(page.getData())) {
                result.addAll(page.getData());
            }
        }
        return result;
    }

    private List<String> getLabelDefs(Long classId) {
        ESCIClassInfo classInfo = ciClassSvc.queryESClassInfoById(classId);
        if (BinaryUtils.isEmpty(classInfo)) {
            return new ArrayList<>();
        }
        List<String> defs = new ArrayList<>();
        classInfo.getCcAttrDefs().forEach(def -> {
            if (def.getIsCiDisp() != null && def.getIsCiDisp() == 1) {
                defs.add(def.getProStdName());
            }
        });
        return defs;
    }

    private String getSysName(ESCIInfo esciInfo) {
        String ciLabel = esciInfo.getCiLabel();
        List<String> datas = JSONObject.parseArray(ciLabel, String.class);
        if (!BinaryUtils.isEmpty(ciLabel) && !CollectionUtils.isEmpty(datas)) {
            String[] strings1 = datas.toArray(new String[0]);
            return StringUtils.join(strings1, ",");
        }

        return formatSysName(esciInfo.getCiPrimaryKey());
    }

    private String formatSysName(String ciPrimaryKey) {
        List<String> strings = JSONObject.parseArray(ciPrimaryKey, String.class);
        if (!CollectionUtils.isEmpty(strings)) {
            strings.remove(0);
            String[] strings1 = strings.toArray(new String[0]);
            return StringUtils.join(strings1, ",");
        }
        return null;
    }

    @Override
    public List<TemplateType> getTemplateList() {
        List<TemplateType> result = new ArrayList<>();
        List<DlvrTemplateDTO> releaseTemplateList = deliverableTemplateService.getReleaseTemplateList(new DlvrTemplateReq());
        if (releaseTemplateList != null && releaseTemplateList.size() > 0) {
            List<Long> typeId = releaseTemplateList.stream().map(DlvrTemplateDTO::getTypeId).collect(Collectors.toList());
            Map<Long, List<DlvrTemplateDTO>> TemplateMap = releaseTemplateList.stream().collect(Collectors.groupingBy(item -> item.getTypeId()));
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            boolQueryBuilder.must(QueryBuilders.termsQuery("id", typeId));
            result = templateTypeDao.getListByQuery(boolQueryBuilder);
            for (TemplateType templateType : result) {
                List<DlvrTemplateDTO> dlvrTemplateDTOList = TemplateMap.get(templateType.getId());
                templateType.setTemplateList(dlvrTemplateDTOList);
            }
        }
        return result;
    }

    @Override
    public CheckPlanModuleRes checkPlanModule(CheckPlanModuleReq req) {
        Assert.notNull(req, "入参不能为空");
        Assert.notNull(req.getPlanId(), "方案id不能为空");
        PlanDesignInstance plan = planDesignInstanceDao.getById(req.getPlanId());
        if (BinaryUtils.isEmpty(plan)) {
            return new CheckPlanModuleRes(false, "该方案已删除");
        }
        if (!BinaryUtils.isEmpty(req.getChapterId())){
            ChapterInstance chapterInstance = planChapterInstanceService.getPlanChapterInstance(req.getChapterId());
            if (BinaryUtils.isEmpty(chapterInstance) || chapterInstance.getDeleted()) {
                return new CheckPlanModuleRes(false, "该章节已删除");
            }
            if (!BinaryUtils.isEmpty(req.getContextId())) {
                ChapterContext context = chapterContextDao.getById(req.getChapterId());
                ContextModule module = null;
                if (!BinaryUtils.isEmpty(context) && !CollectionUtils.isEmpty(context.getModuleList())) {
                    module = context.getModuleList().stream()
                            .collect(Collectors.toMap(ContextModule::getId, Function.identity()))
                            .get(req.getContextId());

                }
                if (BinaryUtils.isEmpty(module)) {
                    return new CheckPlanModuleRes(false, "该内容块已删除");
                }
            }
        }
        return new CheckPlanModuleRes(true, "");
    }

    @Override
    public PlanProcessRelation getPlanByProcessId(String processInstanceId, Long planId) {
        List<PlanProcessRelation> planProcessRelations = planProcessRelationService.getByProcessInstanceId(processInstanceId);
        PlanProcessRelation result = planProcessRelations.stream()
                .filter(relation -> planId.equals(relation.getDesignPlanId()))
                .findFirst()
                .orElse(null);
        return result;
    }

    /**
     * 获取用户信息map
     * @param codes 用户code
     */
    private Map<String, SysUser> queryUserMap(Collection<String> codes) {
        CSysUser cSysUser = new CSysUser();
        cSysUser.setLoginCodes(codes.toArray(new String[0]));
        cSysUser.setSuperUserFlags(new Integer[]{0, 1});
        List<SysUser> userList = userApiSvc.getSysUserByCdt(cSysUser);
        Map<String, SysUser> userIdObjMap = new HashMap<>(userList.size());
        for (SysUser user : userList) {
            user.setLoginPasswd(null);
            String icon = user.getIcon();
            if (icon != null && !icon.startsWith(this.httpResourceUrl)) {
                user.setIcon(httpResourceUrl + icon);
            }
            userIdObjMap.put(user.getLoginCode(), user);
        }
        return userIdObjMap;
    }

}
